package com.heaven.core.framework;

import com.mongodb.client.result.UpdateResult;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

public interface PzService<T>{

    /**
     * 获取 entity 实体主键字段的名字
     * @return 主键字段
     */
    String getEntityPrimaryKeyFieldName();

    /**
     * 获取对应 entity 的 BaseMapper
     *
     * @return BaseMapper
     */
    MongoRepository<T, String> getBaseMapper();

    /**
     * 获取 entity 的 class
     *
     * @return {@link Class<T>}
     */
    Class<T> getEntityClass();

    /**
     * 添加一条记录；当添加的数据主键值已存在就会给库中已经存在的数据做更新操作
     * @param entity 新数据
     * @return 是否添加成功
     */
    boolean save(T entity);


    void saveBatch(T... entities);

    void saveBatch(List<T> entities);

    /**
     * 根据 ID 删除
     * 删除成功返回 1，没有删除数据返回 0
     * 注意此处返回的依据为是否在库里面删除了实际数据
     * @param id 主键ID
     */
    int deleteById(Serializable id);

    /**
     * 根据搜索条件删除
     * @param query 搜索条件
     * @return 删除的数据条数
     */
    long del(Query query);


    /**
     * 删除（根据ID或实体 批量删除）
     *
     * @param idList 主键ID列表或实体列表(不能为 null 以及 empty)
     * @return 只要有元素被删除就返回1，否则返回0
     */
    int deleteBatchIds(Collection<?> idList);

    /**
     * 搜索一个实体
     * @param query 搜索条件
     *              or : new Query().addCriteria(new Criteria().orOperator(Criteria.where(k1).is(v1),...))
     *              and: new Query().addCriteria(new Criteria().andOperator(Criteria.where(k1).is(v1),...))
     * @return 单个结果
     */
    T selectOne(Query query);

    /**
     * 根据 ID 查询
     *
     * @param id 主键ID
     */
    T selectById(Serializable id);

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    List<T> selectBatchIds(Collection<? extends Serializable> idList);

    /**
     * 按照给出的 exampleVideo 实体所包含的非空字段精确查找, 当 exampleVideo 的字段全为空时就是搜索全部
     * @param example exampleVideo 查询条件实体-必须包含非空字段否则为全文检索
     * @return 搜索结果集合
     */
    List<T> selectList(T example);

    /**
     * 混合搜索
     * @param query 搜索条件, 不存在条件就是全文检索; 模糊搜索可以使用正则表达式：
     *              Pattern regex = Pattern.compile("^."+{fieldValue}+".$", Pattern.CASE_INSENSITIVE)
     *              query.addCriteria(Criteria.where({field}).regex(regex))
     * @return 搜索结果集合
     */
    List<T> selectList(Query query);

    /**
     * 分页查询
     * @param query 查询条件 query.with(Sort.by(Sort.Direction.DESC, "字段"))
     * @param pageSize 每页大小
     * @param currentPage 当前页（从第一页开始）
     * @return 查询结果集合
     */
    List<T> selectList(Query query, int pageSize, long currentPage);

    /**
     * 根据 matcher 条件，查询总记录数
     * @param query 查询参数
     */
    Long selectCount(Query query);

    /**
     * @param query 查询参数
     * @param sort Sort.by(Sort.Direction.DESC/ASC, 字段)
     */
    List<T> selectSort(Query query, Sort sort);


    /**
     * 根据 matcher 条件，判断是否存在记录
     *
     * @param query 查询参数
     * @return 是否存在记录
     */
    default boolean exists(Query query) {
        Long count = this.selectCount(query);
        return null != count && count > 0;
    }

    /**
     * 根据搜索条件更新第一条
     *
     * @param query  搜索条件
     * @param update 更新字段
     * @return 更新结果(更新条数，更新数据主键-更新成功返回主键否则返回null，)
     */
    UpdateResult updateOne(Query query, Update update);

    UpdateResult updateOne(Query query, String field, Object value);

    /**
     * 根据搜索条件更新所有符合条件的数据
     * @param query 搜索条件
     * @param update 更新字段
     * @return 更新结果
     */
    UpdateResult updateMulti(Query query, Update update);

    UpdateResult updateById(Serializable id, T entity);
}
